package com.et.u1.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

import com.et.u1.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class BubbleView extends View {

    private final ArrayList<Bubble> mBubbles = new ArrayList<>();
    private final Random random = new Random();
    private int mBubbleRefreshTime = 30;        // 刷新间隔
    private float mBubbleMaxSpeedY = 2.3f;           // 气泡速度
    private float mWaterWidth;                  // 水的宽度
    private float mWaterHeight;                 // 水的高度
    private RectF mContentRectF;                // 实际可用内容区域
    private RectF mWaterRectF;                  // 水占用的区域
    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            addBubble(msg.what);
        }
    };
    private Path mWaterPath;                    // 水
    private Paint mWaterPaint;                  // 水画笔
    private Paint mBubblePaint;                 // 气泡画笔
    private Bitmap bitmap;
    private Thread mBubbleThread;

    public BubbleView(Context context) {
        this(context, null);
    }


    public BubbleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public int getBubbleRefreshTime() {
        return mBubbleRefreshTime;
    }

    public void setBubbleRefreshTime(int mBubbleRefreshTime) {
        this.mBubbleRefreshTime = mBubbleRefreshTime;
        if (mBubbleMaxSpeedY <= 50) {
            mBubbleMaxSpeedY = 2.3f + (((mBubbleRefreshTime - 30) / 10f) * 0.9f);
        } else {
            mBubbleMaxSpeedY = 2.3f + (((mBubbleRefreshTime - 30) / 10f) * 0.7f);
        }
    }

    public void initParams(int w, int h) {

        mWaterRectF = new RectF();
        mWaterWidth = dp2px(w);
        mWaterHeight = dp2px(h);
        mWaterPath = new Path();
        mWaterPaint = new Paint();
        mWaterPaint.setAntiAlias(true);
        initBubble();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mContentRectF = new RectF(0, 0, w, h);

        float bl = mContentRectF.centerX() - mWaterWidth / 2;
        float br = mContentRectF.centerX() + mWaterWidth / 2;
        float bb = mContentRectF.centerY() + mWaterHeight / 2;

        mWaterPath.reset();
        mWaterPath.moveTo(bl, bb - mWaterHeight);
        mWaterPath.lineTo(bl, bb);
        mWaterPath.quadTo(bl, bb, bl, bb);
        mWaterPath.lineTo(br, bb);
        mWaterPath.quadTo(br, bb, br, bb);
        mWaterPath.lineTo(br, bb - mWaterHeight);
        mWaterPath.close();

        mWaterRectF.set(bl, bb - mWaterHeight, br, bb);

        LinearGradient gradient = new LinearGradient(mWaterRectF.centerX(), mWaterRectF.top,
                mWaterRectF.centerX(), mWaterRectF.bottom, 0x004286f4, 0x00373B44, Shader.TileMode.CLAMP);
        mWaterPaint.setShader(gradient);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mWaterPath, mWaterPaint);
        drawBubble(canvas);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startBubbleSync();
        new TimeThread().start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopBubbleSync();
    }

    // 初始化气泡
    private void initBubble() {
        mBubblePaint = new Paint();
    }

    // 开始气泡线程
    private void startBubbleSync() {
        stopBubbleSync();
        mBubbleThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        sleep(mBubbleRefreshTime);
                        tryCreateBubble();
                        refreshBubbles();
                        postInvalidate();
                    } catch (InterruptedException e) {
                        System.out.println("Bubble线程结束");
                        break;
                    }
                }
            }
        };
        mBubbleThread.start();
    }

    // 停止气泡线程
    private void stopBubbleSync() {
        if (null == mBubbleThread) return;
        mBubbleThread.interrupt();
        mBubbleThread = null;
    }

    // 绘制气泡
    private void drawBubble(Canvas canvas) {
        List<Bubble> list = new ArrayList<>(mBubbles);
        for (Bubble bubble : list) {
            if (null == bubble) continue;
            switch (bubble.id) {
                case 0:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.dian);
                    break;
                case 1:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ji);
                    break;
                case 2:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.gou);
                    break;
                case 3:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.wu);
                    break;
                case 4:
                case 5:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.a);
                    break;
                case 6:
                case 8:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.c);
                    break;
                case 7:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.d);
                    break;
                case 9:
                case 10:
                    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.e);
                    break;
            }
            mBubblePaint.setAlpha(bubble.alpha);
            canvas.drawBitmap(bitmap, bubble.x, bubble.y, mBubblePaint);
        }
    }

    private void addBubble(int a) {
        Bubble b = new Bubble();
        b.id = a;
        switch (a) {
            case 0:
                b.speedY = 2.35f * mBubbleMaxSpeedY;
                break;
            case 1:
                b.speedY = 2.3f * mBubbleMaxSpeedY;
                break;
            case 2:
                b.speedY = 2.25f * mBubbleMaxSpeedY;
                break;
            case 3:
                b.speedY = 2.2f * mBubbleMaxSpeedY;
                break;
        }
        b.x = mWaterRectF.centerX();
        b.y = mWaterRectF.bottom;
        float speedX = random.nextFloat() - 0.5f;
        while (speedX == 0) {
            speedX = random.nextFloat() - 0.5f;
        }
        b.speedX = speedX * (mBubbleRefreshTime / 10f);
        mBubbles.add(b);
    }

    // 尝试创建气泡
    private void tryCreateBubble() {
        if (null == mContentRectF) return;
        // 气泡数量
        int mBubbleMaxSize = 10;
        if (mBubbles.size() >= mBubbleMaxSize) {
            return;
        }
        if (random.nextFloat() < 0.9) {
            return;
        }
        Bubble bubble = new Bubble();
        // 气泡最大id
        int mBubbleMaxId = 10;
        // 气泡最小id
        int mBubbleMinId = 4;
        int radius = random.nextInt(mBubbleMaxId - mBubbleMinId);
        radius += mBubbleMinId;
        float speedY = (random.nextFloat() + 2) * mBubbleMaxSpeedY;
        while (speedY < 0.5) {
            speedY = (random.nextFloat() + 2) * mBubbleMaxSpeedY;
        }
        bubble.id = radius;
        bubble.speedY = speedY;
        bubble.x = mWaterRectF.centerX();
        bubble.y = mWaterRectF.bottom;
        float speedX = random.nextFloat() - 0.5f;
        while (speedX == 0) {
            speedX = random.nextFloat() - 0.5f;
        }
        bubble.speedX = speedX * (mBubbleRefreshTime / 10f);
        mBubbles.add(bubble);
    }

    // 刷新气泡位置，对于超出区域的气泡进行移除
    private void refreshBubbles() {
        List<Bubble> list = new ArrayList<>(mBubbles);
        for (Bubble bubble : list) {
            if (bubble.y - bubble.speedY <= mWaterRectF.top + bubble.id || bubble.alpha <= 0) {
                mBubbles.remove(bubble);
            } else {
                int i = mBubbles.indexOf(bubble);
                if (bubble.x + bubble.speedX <= mWaterRectF.left + bubble.id) {
                    bubble.x = mWaterRectF.left + bubble.id;
                } else bubble.x = Math.min(bubble.x + bubble.speedX, mWaterRectF.right - bubble.id);
                bubble.y = bubble.y - bubble.speedY;
                if (bubble.alpha > 0) {
                    bubble.alpha -= mBubbleMaxSpeedY / 5;

                } else {
                    mBubbles.remove(bubble);
                }
                mBubbles.set(i, bubble);
            }
        }
    }

    private float dp2px(float dpValue) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics());
    }

    private static class Bubble {
        int id;     // 气泡id
        float speedY;   // 上升速度
        float speedX;   // 平移速度
        float x;        // 气泡x坐标
        float y;        // 气泡y坐标
        int alpha = 255;//气泡透明度
    }

    private class TimeThread extends Thread {
        @Override
        public void run() {
            do {
                try {
                    int time = mBubbleRefreshTime * 2 + 500;
                    sleep(time);
                    Message msg0 = new Message();
                    msg0.what = 0;
                    mHandler.sendMessage(msg0);

                    sleep(time);
                    Message msg1 = new Message();
                    msg1.what = 1;
                    mHandler.sendMessage(msg1);

                    sleep(time);
                    Message msg2 = new Message();
                    msg2.what = 2;
                    mHandler.sendMessage(msg2);

                    sleep(time);
                    Message msg3 = new Message();
                    msg3.what = 3;
                    mHandler.sendMessage(msg3);

                    sleep(time * 4 + 1000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } while (true);
        }
    }
}
